
#ifndef RENDERER_H_
#define RENDERER_H_

#include <functional>
#include <memory>
#include <string>

#include "display_options.h"
#include "terminal_canvas.h"

namespace tv {
// A renderer for framebuffers. The renderer provides a callback to which
// a framebuffer can be sent; the renderer then takes care of actually
// sending it to the screen, depending on the grid configuration.
class Renderer {
public:
  // A function to write a framebuffer and its offset with timing.
  // This callback is handed over to each ImageSource::SendFrames to
  // emit their content.
  using WriteFramebufferFun =
      std::function<void(int x, int dy, const Framebuffer &fb, SeqType seq_type,
                         Duration end_of_frame)>;

  // Create a renderer that writes to the terminal canvas.
  // The single column vs. multi column are different implementations.
  static std::unique_ptr<Renderer> Create(tv::TerminalCanvas *output,
                                          const DisplayOptions &display_opts,
                                          int cols, int rows,
                                          Duration wait_between_images,
                                          Duration wait_between_rows);

  virtual ~Renderer() {}

  // Create a sink for a new rendering with a title.
  // Returns a callback in which the receiver can send a frambebufer to be
  // rendered, to be called by whoever provides a framebuffer.
  // The returned call can be used to output multiple frames with the usual
  // (x, dy) positioning.
  virtual WriteFramebufferFun render_cb(const std::string &title) = 0;

  // Wait if needed between image sources.
  virtual void MaybeWaitBetweenImageSources() const = 0;

protected:
  Renderer(tv::TerminalCanvas *canvas, const DisplayOptions &display_opts);

  // Trim and potentially title for rendering, obeying the column-width
  // and centering constraints. Adds a newline as this needs to be printed.
  std::string TrimTitle(const std::string &title, int width) const;

  tv::TerminalCanvas *const canvas_;
  const DisplayOptions &options_;
};
} // namespace tv
#endif // RENDERER_H_
